import axios, { AxiosResponse, AxiosRequestConfig } from "axios";
import { session } from '@/plugins/storage';
import { Message } from 'element-ui';
import { user } from '../user';
import Qs from 'qs';

axios.defaults.timeout = 10000;
axios.interceptors.request.use((config: AxiosRequestConfig) => {
    config.headers['X-Auth-Token'] = user.token;

    return config;
});
axios.interceptors.response.use((response: AxiosResponse) => {
    // 如果返回数据中有sessionID就缓存该值
    if (response.headers.hasOwnProperty('x-auth-token')) {
        user.token = response.headers['x-auth-token'];
    }

    // 如果当前用户未登录,则触发未登录事件
    if (response.data && response.data.code === 'NoLogin') {
        user.clear();
    }

    return response;
});

export interface HttpResponse {
    success: boolean;
    message?: string;
    data?: any;
}

export default class Http {
    private propertyBaseUrl: string = '';
    private propertyDebug: boolean = false;

    /** 获取 服务器地址 */
    get baseUrl(): string {
        return this.propertyBaseUrl;
    }


    /** 设置 服务器地址 */
    set baseUrl(v: string) {
        this.propertyBaseUrl = v;
    }

    /** 设置 是否开启DEBUG */
    set debug(v: boolean) {
        this.propertyDebug = v;
    }

    /** 带认证信息的头 */
    get headers(): any {
        return { 'X-Auth-Token': user.token };
    }
    
    /**
     * 略缩图
     */
    public thumb(code: string, def?: string) {
        return code ? (this.baseUrl + '/down/thumb/' + code) : def;
    }

    /**
     * 略缩图
     */
    public iamge(code: string) {
        return this.baseUrl + '/down/iamge/' + code;
    }

    /**
     * 下载地址
     */
    public down(url: string, param: any = {}) {
        const query: string[] = [];

        // 将数据添加到请求参数
        for (const key of Object.keys(param)) {
            query.push(key + '=' + encodeURIComponent(param[key]));
        }

        // 添加登录信息到请求参数
        query.push('SESSIONID=' + user.token);

        // 构建最终请求地址
        return this.baseUrl + url + '?' + query.join('&');
    }

    /**
     * 通过GET请求加载数据(非服务器地址)
     * @param url 请求地址
     * @param params 请求参数
     */
    public reqGet(url: string, params?: any): Promise<any> {
        return new Promise<any>((resolve, reject) => {
            axios.request({
                url: url,
                method: 'GET',
                params: params,
                withCredentials: true,
                paramsSerializer: (d) => {
                    return Qs.stringify(d, { arrayFormat: 'repeat' });
                }
            }).then((response: AxiosResponse<any>) => {
                resolve(response.data);
            }).catch((err: any) => {
                reject(this.error(err));
            });
        });
    }

    /**
     * 通过JSON请求加载数据(非服务器地址)
     * @param url 请求地址
     * @param data 请求参数
     */
    public reqJson(url: string, data?: any): Promise<any> {
        return new Promise<any>((resolve, reject) => {
            axios.request({
                url: url,
                data: data,
                method: 'POST',
                withCredentials: true
            }).then((response: AxiosResponse<any>) => {
                resolve(response.data);
            }).catch((err: any) => {
                reject(this.error(err));
            });
        });
    }

    /**
     * 通过POST请求加载数据(非服务器地址)
     * @param url 请求地址
     * @param data 请求参数
     */
    public reqPost(url: string, data?: any): Promise<any> {
        return new Promise<any>((resolve, reject) => {
            axios.request({
                url: url,
                data: data,
                method: 'POST',
                withCredentials: true,
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                transformRequest: (d) => Qs.stringify(d, { arrayFormat: 'repeat' })
            }).then((response: AxiosResponse<any>) => {
                resolve(response.data);
            }).catch((err: any) => {
                reject(this.error(err));
            });
        });
    }

    /**
     * 通过GET请求加载数据
     * @param url 请求地址
     * @param params 请求参数
     */
    public doGet(url: string, params?: any): Promise<HttpResponse> {
        // 如果开了propertyDebug，就直接请求debug地址
        if (this.propertyDebug) return this.doDebug(url, params);

        return new Promise<HttpResponse>((resolve, reject) => {
            axios.request({
                url: url,
                method: 'GET',
                params: params,
                withCredentials: true,
                baseURL: this.propertyBaseUrl,
                paramsSerializer: (d) => {
                    return Qs.stringify(d, { arrayFormat: 'repeat' });
                }
            }).then((response: AxiosResponse<any>) => {
                const result: HttpResponse = response.data;

                if (result.success === false) {
                    reject(this.error(result));
                } else {
                    resolve(result);
                }
            }).catch((err: any) => {
                reject(this.error(err));
            });
        });
    }

    /**
     * 通过JSON请求加载数据
     * @param url 请求地址
     * @param data 请求参数
     */
    public doJson(url: string, data?: any): Promise<HttpResponse> {
        // 如果开了propertyDebug，就直接请求debug地址
        if (this.propertyDebug) return this.doDebug(url, data);

        return new Promise<HttpResponse>((resolve, reject) => {
            axios.request({
                url: url,
                data: data,
                method: 'POST',
                withCredentials: true,
                baseURL: this.propertyBaseUrl
            }).then((response: AxiosResponse<any>) => {
                const result: HttpResponse = response.data;

                if (result.success === false) {
                    reject(this.error(result));
                } else {
                    resolve(result);
                }
            }).catch((err: any) => {
                reject(this.error(err));
            });
        });
    }

    /**
     * 通过POST请求加载数据
     * @param url 请求地址
     * @param data 请求参数
     */
    public doPost(url: string, data?: any): Promise<HttpResponse> {
        // 如果开了propertyDebug，就直接请求debug地址
        if (this.propertyDebug) return this.doDebug(url, data);

        return new Promise<HttpResponse>((resolve, reject) => {
            axios.request({
                url: url,
                data: data,
                method: 'POST',
                withCredentials: true,
                baseURL: this.propertyBaseUrl,
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                transformRequest: (d) => Qs.stringify(d, { arrayFormat: 'repeat' })
            }).then((response: AxiosResponse<any>) => {
                const result: HttpResponse = response.data;

                if (result.success === false) {
                    reject(this.error(result));
                } else {
                    resolve(result);
                }
            }).catch((err: any) => {
                reject(this.error(err));
            });
        });
    }

    /**
     * 通过缓存加载数据(GET)
     * @param url 请求地址
     * @param params 请求参数
     */
    public doCache(url: string, params?: any): Promise<HttpResponse> {
        // 如果开了propertyDebug，就直接请求debug地址
        if (this.propertyDebug) return this.doDebug(url, params);

        return new Promise<HttpResponse>((resolve, reject) => {
            const cacheKey = 'cache-get-' + url;
            const cacheValue = session.getObj(cacheKey);

            // 验证缓存是否有效，如果缓存无效就重新发起请求
            if (!cacheValue || !cacheValue.success) {
                axios.request({
                    url: url,
                    method: 'GET',
                    params: params,
                    withCredentials: true,
                    baseURL: this.propertyBaseUrl,
                    paramsSerializer: (d) => {
                        return Qs.stringify(d, { arrayFormat: 'repeat' });
                    }
                }).then((response: AxiosResponse<any>) => {
                    const result: HttpResponse = response.data;

                    if (result.success === false) {
                        reject(this.error(result));
                    } else {
                        // 缓存数据
                        session.save(cacheKey, result);

                        // 返回数据
                        resolve(result);
                    }
                }).catch((err: any) => {
                    reject(this.error(err));
                });
            } else {
                resolve(cacheValue);
            }
        });
    }

    /**
     * 请求错误提示组件
     * @param err 错误信息
     */
    private error(err: any): any {
        if (err && err.response && err.response.statusText) {
            Message.error('请求异常：' + err.response.statusText);
        } else if (err && err.response && err.response.status) {
            Message.error('请求异常(错误代码)：' + err.response.status);
        } else if (err && err.message) {
            Message.error('响应错误：' + err.message);
        } else if (err && err.code) {
            Message.error('响应错误(错误代码)：' + err.code);
        } else {
            Message.error('未知错误');
        }

        return err;
    }

    /**
     * propertyDebug请求
     * @param url URL地址 
     * @param params 参数
     */
    private doDebug(url: string, params?: any): Promise<HttpResponse> {
        return new Promise<HttpResponse>((resolve, reject) => {
            axios.request({
                url: url,
                method: 'GET',
                params: params,
                baseURL: '/assets/debug'
            }).then((response: AxiosResponse<any>) => {
                const result: HttpResponse = response.data;

                if (result.success === false) {
                    reject(this.error(result));
                } else {
                    resolve(result);
                }
            }).catch((err: any) => {
                reject(this.error(err));
            });
        });
    }
}
